package com.turingoal.license.checker;

import cn.hutool.core.net.NetUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.http.HttpUtil;
import cn.hutool.system.oshi.OshiUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

/**
 * license校验工具
 */
public final class TgLicenseChecker {
    private static final byte[] header = {'t', 'U', 'r', 'l', 'n', 'G', '0', 'A', 'l'}; // 头部
    private static Logger logger = LoggerFactory.getLogger("license检测"); // 日志
    private static String licenseServerDomain = TgConstantLicenseConfig.SERVER_DOMAIN; // license检查server
    private static String licenseCheckUrl = TgConstantLicenseConfig.LICENSE_CHECK_URL; // license检查url
    private static String licenseInfoUrl = TgConstantLicenseConfig.LICENSE_INFO_URL;  // license信息url
    private static String packageName = ""; // 当前项目包名
    private static Integer port; // 当前项目端口
    private static String contextPath; // 当前项目contextPath

    private TgLicenseChecker() {
        throw new Error("工具类不能实例化！");
    }

    /**
     * 检查初始化。不执行
     */
    public static void init(final Class<?> c, final Integer portParam, final String contextPathParam, final String licenseServerDomainParam, final String licenseCheckUrlParam, final String licenseInfoUrlParam) {
        if (TgLicenseUtil.isNotBlank(licenseServerDomainParam)) {
            licenseServerDomain = licenseServerDomainParam; // license检查server
        }
        if (TgLicenseUtil.isNotBlank(licenseCheckUrlParam)) {
            licenseCheckUrl = licenseCheckUrlParam; // license检查url
        }
        if (TgLicenseUtil.isNotBlank(licenseInfoUrlParam)) {
            licenseInfoUrl = licenseInfoUrlParam; // license信息url
        }
        packageName = c.getPackage().getName(); // 包名
        port = portParam; // 端口
        contextPath = contextPathParam; // 当前项目contextPath
    }

    /**
     * 检查初始化。只能调用一次
     */
    public static void start() {
        checkAll(true); // 执行一次检查
        LocalDateTime currentTime = LocalDateTime.now();
        int checkHout = currentTime.getHour() + 10;
        if (checkHout > 23) {
            checkHout = checkHout - 24;
        }
        // 秒- 分-小时-几号-月份-星期几
        CronUtil.setMatchSecond(true); // 秒匹配
        CronUtil.schedule(currentTime.getSecond() + " " + currentTime.getMinute() + " " + checkHout + " * * ? ", new Task() {
            @Override
            public void execute() {
                TgLicenseChecker.logger.info("*************** check license start ***************");
                TgLicenseChecker.checkAll(false);
                TgLicenseChecker.logger.info("*************** check license end   ***************");
            }
        });
        CronUtil.start(); // 启动
    }

    /**
     * 检查deviceId。true: 有效
     */
    private static boolean checkDeviceId(final TgLicense licenseInfo) {
        boolean result = true;
        if (TgLicenseUtil.isNotBlank(licenseInfo.getDeviceId())) {
            String deviceId = licenseInfo.getDeviceId().trim().toLowerCase();
            try {
                String devId = OshiUtil.getSystem().getSerialNumber();
                if (devId != null) {
                    result = devId.trim().toLowerCase().equals(deviceId);
                }
            } catch (Exception e) {
                result = false;
                logger.error("*************** 对不起，获取不到获取不到deviceId！ ***************");
            }
        }
        return result;
    }

    /**
     * 检查ip地址。true: 有效
     */
    private static boolean checkIp(final TgLicense licenseInfo) {
        boolean result = true;
        if (TgLicenseUtil.isNotBlank(licenseInfo.getIpAddress())) {
            String ip = licenseInfo.getIpAddress().trim();
            try {
                List<String> ips = TgLicenseUtil.getLocalIpList();
                if (ips != null && !ips.isEmpty()) {
                    result = ips.contains(ip);
                }
            } catch (Exception e) {
                result = false;
                logger.error("*************** 对不起，获取不到IP地址！ ***************");
            }
        }
        return result;
    }

    /**
     * 检查mac地址。true: 有效
     */
    private static boolean checkMac(final TgLicense licenseInfo) {
        boolean result = true;
        if (TgLicenseUtil.isNotBlank(licenseInfo.getMacAddress())) {
            String mac = licenseInfo.getMacAddress().trim().toLowerCase();
            try {
                List<String> macs = TgLicenseUtil.getAllMacAddress();
                if (macs != null && !macs.isEmpty()) {
                    result = macs.contains(mac);
                }
            } catch (Exception e) {
                result = false;
                logger.error("*************** 对不起，获取不到MAC地址！ ***************");
            }
        }
        return result;
    }

    /**
     * 检查
     */
    public static void checkAll() {
        checkAll(false);
    }

    /**
     * 检查
     */
    static void checkAll(final boolean first) {
        boolean ok = true; // 是否正常
        TgLicense licenseInfo = getLicenseInfo();
        if (licenseInfo != null) {
            if (!licenseInfo.isExist()) {
                ok = false;
                logger.error("****** 对不起，您的license文件不存在或有错，请联系管理员！ ******");
            } else if (!licenseInfo.isOk()) { // 检查license是否合法
                ok = false;
                logger.error("****** 对不起，您的license文件不合法，请联系管理员！ ******");
            } else if (licenseInfo.isChanged()) { // 检查license是否被篡改
                ok = false;
                logger.error("****** 对不起，您的license文件被非法修改，请联系管理员！ ******");
            } else if (!packageName.equals(licenseInfo.getPackageName())) {  // 检查license是否是当前产品的
                ok = false;
                logger.error("****** 对不起，您的license不属于当前产品，请联系管理员！ ******");
            } else if (!TgLicenseChecker.checkDeviceId(licenseInfo)) { // 验证deviceId
                ok = false;
                logger.error("****** 对不起，本机deviceId与license不匹配，请联系管理员！ ******");
            } else if (!TgLicenseChecker.checkIp(licenseInfo)) { // 验证ip地址
                ok = false;
                logger.error("****** 对不起，本机IP地址与license不匹配，请联系管理员！ ******");
            } else if (!TgLicenseChecker.checkMac(licenseInfo)) {  // 验证mac地址
                ok = false;
                logger.error("****** 对不起，本机MAC地址与license不匹配，请联系管理员！ ******");
            } else if (licenseInfo.isExpired()) { // 检查license是否过期
                ok = false;
                logger.error("****** 对不起，您的license已过期，请联系管理员！ ******");
            } else if (TgConstantLicenseTypes.LICENSE_TYPE_DEV.equals(licenseInfo.getLicenseType())) {  // 开发版
                logger.warn("*************** 您现在使用的是开发版！ ***************");
                if (!first) { // 不是第一次启动
                    ok = false;
                    logger.error("对不起，您现在使用的是开发版，每天会定时停止运行！");
                }
            } else if (TgConstantLicenseTypes.LICENSE_TYPE_FREE.equals(licenseInfo.getLicenseType())) {
                // 免费版
                logger.info("*************** 您现在使用的是免费版！ ***************");
            } else { // 正式版
                logger.info("*************** 系统检测 ***************");
            }
            if (TgLicenseUtil.isNotBlank(licenseInfo.getExpiryDate())) {
                LocalDate expireDate = LocalDate.parse(licenseInfo.getExpiryDate());
                LocalDate currentDate = LocalDate.now();
                if (currentDate.isBefore(expireDate) && currentDate.isAfter(expireDate.minusDays(30))) { // 不足30天
                    // logger.error
                    System.err.println("****** ---当您看到这条消息，说明您的license到期时间已经不足30天，请联系相关人员续期！ --- ******");
                    System.err.println("****** ---license预计到期时间：" + licenseInfo.getExpiryDate() + "！ --------  当前时间：" + currentDate + "  -------- ******");
                    System.err.println("****** ---license到期后系统将无法启动，运行中的系统会自动停止运行！！！ --------------- ******");
                    System.err.println("****** ---对于删除license校验、非法修改等破解license等行为，将追究相关法律责任！ ------- ******");
                }
            }
            if (NetUtil.ping(licenseServerDomain)) {
                try {
                    sendInfo(licenseInfo); // 发送信息到服务器
                } catch (Exception e) {
                    logger.info("*************** " + e.getMessage() + " ***************");
                }
            }
        } else {
            ok = false;
            logger.error("****** 对不起，license文件不存在！ ******");
        }
        if (!ok) {
            System.exit(0); // 系统退出
        }
    }

    /**
     * 读取license
     */
    public static final TgLicense getLicenseInfo() {
        TgLicense licenseInfo = TgLicenseCheckUtil.readLicense(TgConstantLicenseConfig.LICENSE_FILE_PATH, header);
        if (licenseInfo != null) {
            if (TgLicenseUtil.isNotBlank(licenseInfo.getLicenseId())) {
                licenseInfo.setLicenseInfoUrl(licenseInfoUrl + "/" + licenseInfo.getLicenseId());
            }
            if (TgLicenseUtil.isNotBlank(licenseInfo.getExpiryDate())) {
                LocalDate expiryDate = LocalDate.parse(licenseInfo.getExpiryDate());
                if (LocalDate.now().isAfter(expiryDate)) {
                    licenseInfo.setExpired(true); // 是否过期
                }
            }
            if (TgLicenseUtil.isNotBlank(licenseInfo.getLicenseSign())) { // 有签名
                String licenseSignStr = licenseInfo.getLicenseSign().toLowerCase();
                String signStr = TgLicenseSignUtil.sign(licenseInfo).toLowerCase();
                if (!signStr.equals(licenseSignStr)) { // 文件被篡改
                    licenseInfo.setChanged(true);
                }
            } else { // 签名不存在，文件被篡改
                licenseInfo.setChanged(true);
            }
            if (TgConstantLicenseTypes.LICENSE_TYPE_DEV.equals(licenseInfo.getLicenseType())) {  // 开发版
                logger.warn("*************** 开发版 ***************");
            } else if (TgConstantLicenseTypes.LICENSE_TYPE_FREE.equals(licenseInfo.getLicenseType())) {   // 免费版
                logger.info("*************** 免费版 ***************");
            } else {
                logger.info("*************** 专业版 ***************");
            }
        }
        return licenseInfo;
    }

    /**
     * 发送信息到服务器
     */
    public static void sendInfo(final TgLicense tgLicenseInfo) {
        HashMap<String, Object> paramMap = new HashMap<>();
        if (tgLicenseInfo != null && tgLicenseInfo.isExist()) {
            paramMap.put("licenseId", tgLicenseInfo.getLicenseId()); // licenseId
            paramMap.put("packageName", tgLicenseInfo.getPackageName()); // 包名
            paramMap.put("product", tgLicenseInfo.getProduct()); // 产品
            paramMap.put("licenseType", tgLicenseInfo.getLicenseType()); // 授权类型
            paramMap.put("issuedDate", tgLicenseInfo.getIssuedDate()); // 生效日期
            paramMap.put("expiryDate", tgLicenseInfo.getExpiryDate());  // 过期日期
            paramMap.put("versionName", tgLicenseInfo.getVersionName());  // 版本
            paramMap.put("customer", tgLicenseInfo.getCustomer()); // 客户。企业的是企业名称，个人的是个人姓名
            paramMap.put("customerType", tgLicenseInfo.getCustomerType()); // 客户类型: 企业, 个人
            paramMap.put("customerCodeNum", tgLicenseInfo.getCustomerCodeNum()); // 客户编码。企业的是企业信用代码，个人的是个人身份证号
            paramMap.put("deviceId", tgLicenseInfo.getDeviceId());  // deviceId
            paramMap.put("ipAddress", tgLicenseInfo.getIpAddress());  // IP地址
            paramMap.put("macAddress", tgLicenseInfo.getMacAddress());  // mac地址
            paramMap.put("exist", tgLicenseInfo.isExist()); // 是否存在
            paramMap.put("ok", tgLicenseInfo.isOk()); // 合法
            paramMap.put("expired", tgLicenseInfo.isExpired()); // 是否过期
            paramMap.put("changed", tgLicenseInfo.isChanged()); // 是否被篡改
            String requestDeviceId = OshiUtil.getSystem().getSerialNumber(); // request deviceId
            if (requestDeviceId != null) {
                paramMap.put("requestDeviceId", requestDeviceId); // request deviceId
            }
            String requestMac = NetUtil.getLocalMacAddress();
            if (requestMac != null) {
                paramMap.put("requestMacAddress", requestMac); // request MAC
            }
            // "requestIpAddress"
            paramMap.put("requestPort", port); // port
            paramMap.put("requestContextPath", contextPath); // contextPath
        } else {
            paramMap.put("exist", false); // 文件不存在
        }
        HttpUtil.post(licenseCheckUrl, paramMap);
    }
}
